﻿#region Creditos

/* Autor: Edilberto Sánchez Forero	*/
/* Email: esanchezfo@gmail.com		*/
/* Licencia: LGPL, Software Libre	*/
/* País: Colombia, Bogotá			*/

#endregion

#region Librerias

using System;
using System.Text;
using System.Web;
using System.Web.Security;

using ESF.General;
using ESF.SSO.Core.Entities;
using ESF.Web;
using System.IO;
using System.Collections.Generic;
using ESF.SSO.Core.Entities.BasicReferences;
using ESF.General.Entity;
using System.Diagnostics;
using System.Net;

#endregion


namespace ESF.SSO.Web.Tools.Modules
{
	public class AuthenticationModule : IHttpModule
    {
		#region Constantes de Configuracion

		private const string KEY_SSOMAIN_URL = "ESF.SSO.MainURL";
		
		private const string KEY_SSOLOGIN_URL = "ESF.SSO.LoginURL";

		private const string KEY_SSOTIMEOUT_URL = "ESF.SSO.TimeOutURL";

		private const string KEY_SSOLINKTARGET = "ESF.SSO.LinkTarget";

		private const string TICKET_NAME = "ESF.SSO.TicketName";
		
		private const string TICKET_DOMAIN = "ESF.SSO.TicketDomain";

		internal const string SESSIONID_NAME = "ESF.SSO.SessionID";

		private const string TICKET_COOKIE_PATH = "/";
		
		private const string USERMENUITEMSBASE = "{0}_{1}_MENUITEMS";
		
		private const string USERRIGHTSBASE = "{0}_RIGHTS";
		
		private const string USERAPPLISTKEYBASE = "{0}_{1}_APPLIST";
		
		internal const string RETURNURL = "ReturnURL";
		
		#endregion


		#region Miembros

		/// <summary>
		/// Aplicacion Http
		/// </summary>
		private HttpApplication _HttpApp;

		#endregion


		#region Propiedades de Configuracion
		
		public static string LinkTarget
		{
			get
			{
				return ReadConfig.GetAppSetting (KEY_SSOLINKTARGET, "_top");
			}
		}


		private static string LoginURL
		{
			get
			{
				return ReadConfig.GetAppSetting (KEY_SSOLOGIN_URL, ReadConfig.MainURL);
			}
		}


		private static string TimeOutURL
		{
			get
			{
				return ReadConfig.GetAppSetting (KEY_SSOTIMEOUT_URL, ReadConfig.MainURL);
			}
		}
		
		
		public static string SSOClientMainURL
		{
			get { return ReadConfig.GetAppSetting (KEY_SSOMAIN_URL) + "/Client/"; }
		}
		
		
		public static string SSOAdminMainURL
		{
			get { return ReadConfig.GetAppSetting (KEY_SSOMAIN_URL) + "/Admin/"; }
		}
		
		
		public static string TicketDomain
		{
			get 
			{ 
				return ReadConfig.GetAppSetting(TICKET_DOMAIN, PageHelper.PageDomain);
			}
		}
		
		#endregion


		#region Propiedades del Usuario

		public static bool IsAuthenticated
		{
			get
			{
				return HttpContext.Current.User.Identity.IsAuthenticated;
			}
		}
		
		
		public static string SignedInUserAlias
		{
			get
			{
				return HttpContext.Current.User.Identity.Name;
			}
		}
		
		
		private static string ApplicationCode
		{
			get
			{
				string appCode;
					
					
				appCode = null;
				
				if (HttpContext.Current.Session != null)
				{				
					appCode = HttpContext.Current.Session ["ApplicationCode"] as string;
				}
				
				if (TextHelper.IsEmpty (appCode))
				{
					appCode = HttpContext.Current.Request.QueryString ["ApplicationCode"];	
				}
				
				if (TextHelper.IsEmpty (appCode))
				{
					appCode = ReadConfig.ApplicationCode;
				}
			
				ApplicationCode = appCode;
			
				return appCode;
			}
			set
			{
				HttpContext.Current.Session ["ApplicationCode"] = value;
			}
		}
		
		
		public static bool GetUserRightBool (string pRightCode)
		{
			return TextHelper.GetBool (GetUserRightString (pRightCode), false);
		}


		public static int GetUserRightInt32 (string pRightCode)
		{
			return TextHelper.GetInt (GetUserRightString (pRightCode));
		}
		
		
		public static string GetUserRightString (string pRightCode)
		{
			BasicReference value;


			value = UserRights.Find (r => String.Compare (r.Code, pRightCode, true) == 0);

			if (value == null) { return string.Empty; }

			return value.Value;
		}


		internal static List<BasicReference> UserRights
		{
			get
			{
				List<BasicReference> userRights;
			
			
				if (!IsAuthenticated)
				{
					return new List<BasicReference> ();
				}

				//userRights = (HttpContext.Current.Session [string.Format (USERRIGHTSBASE, SignedInUserAlias)] as List<BasicReference>);
			
				//if (userRights == null)
				//{
					using (SSOServiceClient.SSOServiceClient ssoClient = new SSOServiceClient.SSOServiceClient ())
					{
						userRights = ssoClient.GetUserRights (SignedInUser);
					}
				//}UserRights = 
				
				return userRights;
			}
			//set
			//{
			//    HttpContext.Current.Session [string.Format (USERRIGHTSBASE, SignedInUserAlias)] = value;
			//}
		}
		
		
		public static List<UserMenuItem> UserMenuItems
		{
			get
			{
				
				using (SSOServiceClient.SSOServiceClient ssoClient = new SSOServiceClient.SSOServiceClient ())
				{				
					return ssoClient.GetUserMenu (SignedInUser, new BasicReference () { Code = ApplicationCode });
				}
			}
		}
		
		
		public static List<UserMenuItem> UserApplicationList
		{
			get 
			{
				//return WebCacheHelper.GetAddDay<List<UserMenuItem>> (
				//	string.Format (USERAPPLISTKEYBASE, ApplicationCode, SignedInUserAlias),
				//	delegate ()
				//	{
						using (SSOServiceClient.SSOServiceClient ssoClient = new ESF.SSO.Web.Tools.SSOServiceClient.SSOServiceClient ())
						{
							return ssoClient.GetUserApplicationList (SignedInUser);
						}
				//	});
			}
		}

		#endregion


		#region Propiedades del Ticket

		public static string SessionID
		{
			get 
			{
				return SignedInUser.SessionID;
			}
		}


		public static User SignedInUser
		{
			internal set
			{
				PrincipalUser currentUser = new PrincipalUser (value);
				
				HttpContext.Current.User = currentUser;

				HttpContext.Current.Trace.Write(string.Format ("AuthenticationModule.SignedInUser Set With: {0}, User: {1}", value, currentUser.Identity.Name)); 

				Ticket = currentUser.EncryptedTicket;
				
				HttpContext.Current.Trace.Write ("AuthenticationModule.SignedInUser Set End");
			}
			get 
			{
				PrincipalUser prinUser;
				
				
				HttpContext.Current.Trace.Write ("AuthenticationModule.SignedInUser Get Return");
			
				prinUser = HttpContext.Current.User as PrincipalUser;

				
				if (prinUser == null)
				{
					HttpContext.Current.Trace.Write("AuthenticationModule.SignedInUser Get With: Anonimo"); 

					return new User ();
				}

				HttpContext.Current.Trace.Write(string.Format("AuthenticationModule.SignedInUser Get With: {0}", prinUser.Identity.Name)); 

				return prinUser.User;
			}
		}


		private static string Ticket
		{
			set
			{
				HttpCookie cookie;
				
				PrincipalUser objCP;
			
			
				cookie = HttpContext.Current.Request.Cookies[TICKET_NAME];

				// Solo si la galleta no esta o su contenido es diferente se pone
				// La duraccion de la galleta por defecto sera el tiempo de la sesion
				if (cookie == null || cookie.Value != value)
				{
					cookie = new HttpCookie (TICKET_NAME);
					cookie.Domain = TicketDomain;
					cookie.Path = TICKET_COOKIE_PATH;
				
					if (string.IsNullOrEmpty (value))
					{
						cookie.Value = string.Empty;
						cookie.Expires = DateTime.Now.AddDays (-30);
					}
					else
					{
						objCP = new PrincipalUser (value);
						
						cookie.Value = value;
						//cookie.Expires = DateTime.MaxValue;
						//cookie.Expires = objCP.User.SessionExpirationDateTime;
					}
				
					HttpContext.Current.Trace.Write (
						string.Format ("Setting cookie: Path -> {0} Name -> {1} Domain -> {2} Expires -> {3} Value -> {4}",
							cookie.Path, cookie.Name, cookie.Domain, cookie.Expires, cookie.Value));

					HttpContext.Current.Response.Cookies.Set (cookie);
				}
			}
			get
			{
				string strTicket;
				string strSessionID;

				HttpCookie cookie;
				
				
				cookie = HttpContext.Current.Request.Cookies[TICKET_NAME];
				
				strSessionID = HttpContext.Current.Request.QueryString [SESSIONID_NAME];

				if (string.IsNullOrEmpty (strSessionID) && HttpContext.Current.Request.UrlReferrer != null)
				{
					strSessionID = RequestHelper.GetQueryStringValue (HttpContext.Current.Request.UrlReferrer.Query, SESSIONID_NAME);
				}

				
				// Si no hay galleta
				if (cookie == null)
				{
					HttpContext.Current.Trace.Write ("There was no cookie");

					// Se revisa por el indicador de SessionID del GET
					// Si no esta
					if (string.IsNullOrEmpty(strSessionID))
					{
						strTicket = null;
					}
					// Se renueva el ticket
					else
					{
						HttpContext.Current.Trace.Write (string.Format ("Setting Ticket with SessionID {0}", strSessionID));

						using (SSOServiceClient.SSOServiceClient ssoClient = new SSOServiceClient.SSOServiceClient ())
						{
							Ticket = strTicket = new PrincipalUser (ssoClient.GetUserFromSessionID (strSessionID)).EncryptedTicket;
						}
					}
				}
				// Si hay galleta
				else
				{
					HttpContext.Current.Trace.Write (string.Format ("Cookie with value: {0}", cookie.Value));
					
					strTicket = cookie.Value;

					// Si no hay contenido en la galleta
					if (string.IsNullOrEmpty(strTicket))
					{
						HttpContext.Current.Trace.Write ("Cookie empty");

						// Se renueva la sesion si hay un SessionID en el GET
						// Si no esta
						if (string.IsNullOrEmpty(strSessionID))
						{
							strTicket = null;
						}
						// Se renueva el ticket
						else
						{
							HttpContext.Current.Trace.Write(string.Format("Setting Ticket with SessionID {0}", strSessionID));

							using (SSOServiceClient.SSOServiceClient ssoClient = new SSOServiceClient.SSOServiceClient ())
							{
								Ticket = strTicket = new PrincipalUser (ssoClient.GetUserFromSessionID (strSessionID)).EncryptedTicket;
							}
						}
					}
				}

				// Si no hay ticket (desde request sessionid) y no hay cookie no hay cambios
				if (string.IsNullOrEmpty (strTicket) && cookie == null)
				{
					HttpContext.Current.Trace.Write ("Cookie or ticket information not found");

					return null;
				}

				HttpContext.Current.Trace.Write (string.Format ("Ticket found: {0}", strTicket));

				Ticket = strTicket;

				
				return strTicket;
			}
		}

		#endregion


		#region Funciones Utilitarias

		public static void ClearSession ()
		{
			// Verificar manejo de sessionid para diferenciar diferentes contextos de sesion entre aplicaciones con sessiones diferentes

			HttpContext.Current.Session.Clear ();
			HttpContext.Current.Session.Abandon ();

			SignedInUser = null;
		}


		public static void ReturnToMainURL()
		{
		    ReturnToMainURL(HttpContext.Current.Request.Url.OriginalString);
		}


		private static void ReturnToMainURL(string pstrURL)
		{
		    int intTemp;
		    string strTemp;


		    intTemp = pstrURL.IndexOf(SESSIONID_NAME);

		    // Se remueven indicadores de sesion existentes
		    if (intTemp != -1)
		    {
		        strTemp = pstrURL;

		        pstrURL = pstrURL.Substring(0, intTemp - 1);

		        intTemp += SESSIONID_NAME.Length + 1;

		        strTemp = strTemp.Substring(intTemp, strTemp.Length - intTemp);

		        intTemp = strTemp.IndexOf("&");

		        if (intTemp != -1)
		        {
		            strTemp = strTemp.Substring(intTemp, strTemp.Length - intTemp);
		        }
		        else
		        {
		            strTemp = string.Empty;
		        }

		        pstrURL += strTemp;
		    }


			pstrURL = RequestHelper.AppendVarValueToHTTPURL (LoginURL, 
		            RETURNURL, HttpUtility.UrlEncode(pstrURL));

			switch (Path.GetExtension (HttpContext.Current.Request.PhysicalPath).ToLower ())
			{
				case ".aspx":
				case ".asp":
				case ".htm":
				case ".html":
					HttpContext.Current.Response.ClearContent ();

					HttpContext.Current.Response.Write ("<script type=\"text/javascript\">" + JS.GenerateGoTop (pstrURL) + "</script>");
					
				break;		

				default:
					HttpContext.Current.Response.Redirect(pstrURL);
				break;
			}
		}


		#endregion

		
		#region Funciones, IHttpModule

		/// <summary>
		/// Inicializa el modulo (derivado de IHttpModule) cuando es llamado por el entorno de ejecucion
		/// disponiendo del metodo de autenticacion
		/// </summary>
		/// <param name="phtHttpApp">Aplicacion Http</param>
		public void Init(HttpApplication phtHttpApp)
		{
			_HttpApp = phtHttpApp;

			
			_HttpApp.AuthenticateRequest += OnAuthenticate;

			_HttpApp.EndRequest += OnEndRequest;
		}

		#endregion

		
		#region Eventos Http, IHttpModule

		private void OnEndRequest(object sender, EventArgs e)
		{
			_HttpApp = (HttpApplication)sender;

			// No esta autorizado, no autenticado
			if (_HttpApp.Response.StatusCode == (int) HttpStatusCode.Forbidden || _HttpApp.Response.StatusCode == (int) HttpStatusCode.Unauthorized) 
			{
				ReturnToMainURL ();
			}
		}


		/// <summary>
		/// Manejador del evento del requerimiento de autenticacion
		/// </summary>
		private void OnAuthenticate(object sender, EventArgs e)
		{
			HttpContext.Current.Trace.Write ("AuthenticationModule.OnAuthenticate Start");
		
			HttpContext.Current.User = new PrincipalUser (Ticket);
			HttpContext.Current.Trace.Write ("User: " + HttpContext.Current.User.Identity.Name);

			HttpContext.Current.Trace.Write ("AuthenticationModule.OnAuthenticate End");
		}

		#endregion


		#region Funciones, IHttpModule

		public void Dispose() { }

		#endregion		
    }
}
